﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using XPathAutoSuggest;

namespace XPathToolTests {
    /// <summary>
    /// Tests functionality of the class XmlHelper, which does the heavy-lifting of this project such as
    /// suggesting and evaluating XPath queries
    /// </summary>
    [TestFixture]
    public class XmlHelperTest {
        string _SampleXml = @"<?xml version=""1.0"" encoding=""ISO-8859-1""?>
                                <bookstore>
                                    <!--Comment-->
                                    <book>
                                      <title lang=""eng"">Harry Potter</title>
                                      <price>29.99</price>
                                    </book>
                                    <book>
                                        <![CDATA[
                                        function matchwo(a,b)
                                        {
                                        if (a < b && a < 0) then
                                          {
                                          return 1;
                                          }
                                        else
                                          {
                                          return 0;
                                          }
                                        }
                                        ]]>
                                    </book>

                                    <book>
                                      <title lang=""eng"">Learning XML</title>
                                      <price>39.95</price>
                                    </book>
                                    <book>
                                      <title lang=""fr"">Nodes for Dummies</title>
                                      <price>3.95</price>
                                    </book>

                                </bookstore>";

        private string _SampleXml2 = @"<?xml version=""1.0""?>
                                        <countries>
                                          <country name=""America"" size=""large"">
                                            <provinces>
                                              <province>Alabama</province>
                                              <province>Alaska</province>
                                              <province>Arkansas</province>
                                              <province>California</province>
                                            </provinces>
                                            <Products>
                                              <Product name=""Weapons"" />
                                              <Product name=""Culture"" />
                                            </Products>
	                                        <Celebrities>
		                                        <Celebrity name=""Steve Jobs"" />
	                                        </Celebrities>
                                          </country>
                                          <country name=""Canada"" size=""large"">
                                            <provinces>
                                              <province>Alberta</province>
                                              <province>British Columbia</province>
                                              <province>Manitoba</province>
                                            </provinces>
                                          </country>
                                        </countries>";

        /// <summary>
        /// Some basic tests to ensure that we can find the path to selected node
        /// </summary>
        [Test]
        public void GetNodeTest() {
            string tagName, nodeVal;
            int selectionStart = _SampleXml.IndexOf("Harry Potter");
            string indexedPath;
            XmlHelper target = new XmlHelper();
            string nodePath = target.GetNodePath(_SampleXml, "Harry Potter", selectionStart, out tagName, out indexedPath, out nodeVal);
            Assert.AreEqual("/bookstore/book/title", nodePath, "Failed to generate simple node path to /bookstore/book/title");

            selectionStart = _SampleXml.IndexOf("Learning XML");

            nodePath = target.GetNodePath(_SampleXml, "Learning XML", selectionStart, out tagName, out indexedPath, out nodeVal);
            Assert.AreEqual("/bookstore/book/title", nodePath, "Failed to find second instance of /bookstore/book/title");

            selectionStart = _SampleXml.IndexOf("39.95");
            nodePath = target.GetNodePath(_SampleXml, "39.95", selectionStart, out tagName, out indexedPath, out nodeVal);
            Assert.AreEqual("/bookstore/book/price", nodePath);

            selectionStart = _SampleXml.IndexOf("Nodes for Dummies");
            nodePath = target.GetNodePath(_SampleXml, "Nodes for Dummies", selectionStart, out tagName, out indexedPath, out nodeVal);
            Assert.AreEqual("/bookstore/book/title", nodePath);
            Assert.IsTrue(indexedPath.Contains("book[4]"), "Expected the indexed path to contain a reference to the 4th book");
        }

        /// <summary>
        /// If the current index is at the start of a node, we should be able to retreive the node name
        /// </summary>
        [Test]
        public void GetNodeNameTest() {
            int p = 0;
            XmlHelperNode aNode;
            int tagStart = 0;
            XmlHelper target = new XmlHelper();
            target.GetNode(@"<?xml version=""1.0"" encoding=""ISO-8859-1""?><bookstore>", out aNode, ref p, ref tagStart);
            Assert.AreEqual("xml", aNode.NodeName, "Failed to retrieve the node name");
        }


        [Test]
        public void New_XmlNoSde_Handles_Separate_Close_Tag() {
            string newTag = "</book>";
            XmlHelperNode myNode = new XmlHelperNode(newTag);
            Assert.AreEqual(XmlHelperNodeType.ClosingTag, myNode.NodeType);
            Assert.AreEqual("book", myNode.NodeName);
        }

        [Test]
        public void New_XmlNode_HandlesNormal_Tag() {
            string newTag = "<book>";
            XmlHelperNode myNode = new XmlHelperNode(newTag);
            Assert.AreEqual(XmlHelperNodeType.NormalWithClosingTag, myNode.NodeType);
            Assert.AreEqual("book", myNode.NodeName);
        }

        [Test]
        public void New_XmlNode_Handles_Normal_Tag_With_Attribute() {
            string newTag = "<book language=\"eng\">";
            XmlHelperNode myNode = new XmlHelperNode(newTag);
            Assert.AreEqual(XmlHelperNodeType.NormalWithClosingTag, myNode.NodeType);
            Assert.AreEqual("book", myNode.NodeName);
        }

        [Test]
        public void New_XmlNode_Handles_Slash_Close_SameTag() {
            string newNode = "<book />";
            XmlHelperNode myNode = new XmlHelperNode(newNode);
            Assert.AreEqual(XmlHelperNodeType.NormalNoClosingTag, myNode.NodeType);
            Assert.AreEqual("book", myNode.NodeName);
        }

        [Test]
        public void New_XmlNode_Handles_Comment() {
            string newNode = "<!--test comment-->";
            XmlHelperNode myNode = new XmlHelperNode(newNode);
            Assert.AreEqual(XmlHelperNodeType.Comment, myNode.NodeType);
            Assert.AreEqual("test comment", myNode.NodeName);
        }

        [Test]
        public void New_XmlNode_Handles_Question() {
            string newNode = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
            XmlHelperNode myNode = new XmlHelperNode(newNode);
            Assert.AreEqual(XmlHelperNodeType.Question, myNode.NodeType);
            Assert.AreEqual("xml", myNode.NodeName);
        }

        [Test]
        public void New_XmlNode_Handles_CData() {
            string newNode = @"<![CDATA[
                                function matchwo(a,b)
                                {
                                if (a < b && a < 0) then
                                  {
                                  return 1;
                                  }
                                else
                                  {
                                  return 0;
                                  }
                                }
                                //]]>";
            XmlHelperNode cDataNode = new XmlHelperNode(newNode);
            Assert.AreEqual(XmlHelperNodeType.XmlData, cDataNode.NodeType);
        }

        [Test]
        public void Aggregate_Stack_Has_Expected_Sequence() {
            Stack<String> tokens = new Stack<string>();
            tokens.Push("<bookstore>");
            tokens.Push("<books>");
            tokens.Push("<book>");
            tokens.Push("price");
            tokens.Pop();
            string agg = tokens.Reverse<string>().Aggregate((s1, s2) => s1 + s2);
            Console.WriteLine(agg);
            Assert.AreEqual("<bookstore><books><book>", agg);
        }

        [Test]
        public void GetPathFromPoint() {
            string selectedText = @"Learning XML";
            string tagName, nodeVal;
            int selectionStart = _SampleXml.IndexOf(selectedText);
            string indexedPath;
            XmlHelper target = new XmlHelper();
            string nodePath = target.GetNodePath(_SampleXml, selectedText, selectionStart, out tagName, out indexedPath, out nodeVal);
            Assert.AreEqual("/bookstore/book/title", nodePath);
        }

        [Test]
        public void GetNodeVal_Test() {
            int selectionStart = _SampleXml.IndexOf("39.95");
            XmlHelper target = new XmlHelper();
            string nodeVal = target.GetNodeVal(_SampleXml, selectionStart);
            Assert.AreEqual("39.95", nodeVal, "Failed simple node value selection");
        }

        /// <summary>
        /// The utility should correctly return the tag name when we give it the position
        /// </summary>
        /// <remarks>
        /// If we have a node like &lt;title lang="eng"&gt; and the position is on 'eng', 
        /// we should get 'lang' as a result
        /// </remarks>
        [Test]
        public void GetTagNameTest() {
            string allXml = _SampleXml;
            int selPos = 237;
            int p = 240;
            int tagStart = 224;
            string expected = "lang";
            XPathAutoSuggest.XmlHelper target = new XmlHelper();
            string actual = target.GetTagName(allXml, selPos, p, tagStart);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        /// 
        /// </summary>
        [Test]
        public void GetNodeValTest() {
            int selectionStart = _SampleXml.IndexOf("Learning XML");
            //try a point at the very beginning of the node:
            XPathAutoSuggest.XmlHelper target = new XmlHelper();
            string nodeVal = target.GetNodeVal(_SampleXml, selectionStart);
            Assert.AreEqual("Learning XML", nodeVal);

            //Now try a point inside the node
            nodeVal = target.GetNodeVal(_SampleXml, selectionStart + 1);
            Assert.AreEqual("Learning XML", nodeVal);

            //Finally try at the very end of teh node:
            nodeVal = target.GetNodeVal(_SampleXml, selectionStart + "Learning XML".Length - 1);
            Assert.AreEqual("Learning XML", nodeVal);
        }

        [Test]
        public void GetNodePath_MultipleRepeats_Test() {
            int selectionStart = _SampleXml2.IndexOf("Manitoba");
            string tagName;
            System.Collections.Generic.Dictionary<string, int> nodePathCounts = new System.Collections.Generic.Dictionary<string, int>();
            string indexedPath;

            XPathAutoSuggest.XmlHelper target = new XmlHelper();
            string nodeVal = target.GetNodePath(_SampleXml2, "Manitoba", selectionStart, out tagName,
                out indexedPath, out nodeVal);
            System.Diagnostics.Debug.WriteLine(indexedPath);


            selectionStart = _SampleXml.IndexOf("39.95");
            nodeVal = target.GetNodePath(_SampleXml, "39.95", selectionStart, out tagName,
                out indexedPath, out nodeVal);
        }
    }
}
